﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using System.Reflection;
using JackyCode.Mock.Exceptions;
using System.Linq.Expressions;

namespace JackyCode.Mock.Test
{
    [TestFixture]
    public class TestMockData
    {
        private IMockData mockData;
        private MethodData methodData;
        private MethodData outMethodData;

        [SetUp]
        public void Initialize()
        {
            mockData = new MockDataImpl();
            methodData = new MethodData(MethodInfoHelper.GetCReturnStrMethodInfo());
            InitialOutMethodData();
        }

        private void InitialOutMethodData()
        {
            IList<ArgumentDetail> argumentDetails = new List<ArgumentDetail> 
            {
                new ArgumentDetail{ IsNotOut = true,Value = "Input"},
                new ArgumentDetail{ IsNotOut = false,Value = "Output"}
            };
            outMethodData = new MethodData(argumentDetails, MethodInfoHelper.GetIOutMethod());
        }

        [Test]
        public void TestMerge()
        {
            mockData.Merge(methodData, "HelloWorld");
            Assert.AreEqual(1, mockData.Count);
            mockData.Merge(methodData, "HelloWorld");
            Assert.AreEqual(1, mockData.Count);
        }


        [Test]
        public void TestVirMethodNonSetUpReturnDefaultVal()
        {
            Assert.IsNull(mockData.GetReturnVal(new MethodData(MethodInfoHelper.GetCReturnStrMethodInfo())));
            Assert.AreEqual(false, mockData.GetReturnVal(new MethodData(MethodInfoHelper.GetCReturnBoolMethodInfo())));
        }

        [Test]
        public void TestInterfaceMethodNonSetUpReturnDefaultVal()
        {
            Assert.IsNull(
                mockData.GetReturnVal(new MethodData(MethodInfoHelper.GetIReturnStrMethodInfo())));
            Assert.AreEqual(false,
                mockData.GetReturnVal(new MethodData(MethodInfoHelper.GetIReturnBoolMethodInfo())));
        }

        [Test]
        public void TestSetUpMethodExeTimes()
        {
            mockData.Merge(methodData, "HelloWorld");
            for (int i = 1; i < 5; i++)
            {
                mockData.GetReturnVal(methodData);
                Assert.AreEqual(i, mockData.GetExecuteTimes(methodData));
            }
        }

        [Test]
        [ExpectedException(ExpectedException=typeof(MockException),
            ExpectedMessage = "never setup method,can't do this operator!")]
        public void TestNonSetUpMethodExeTimes()
        {
            mockData.GetReturnVal(methodData);
            mockData.GetExecuteTimes(methodData);
        }

        [Test]
        public void TestContrains()
        {
            Assert.IsFalse(mockData.Contains(methodData));
            mockData.Merge(methodData,"Hello");
            Assert.IsTrue(mockData.Contains(methodData));
        }

        [Test]
        public void TestGetReturnValByMethodInfoAndMethodArguments()
        {
            Assert.IsNull(
                mockData.GetReturnVal(MethodInfoHelper.GetCReturnStrMethodInfo(), new object[0]));
        }

        [Test]
        public void TestGetParameterValByIndex()
        {
            MethodInfo methodInfo = MethodInfoHelper.GetIOutMethod();
            mockData.Merge(outMethodData,null);

            Assert.AreEqual("Input", mockData.GetParameterVal(0,methodInfo,new object[]{"Input","Ouput"}));
            Assert.AreEqual("Output", mockData.GetParameterVal(1, methodInfo, new object[] { "Input", "Ouput" }));
        }

        [Test]
        public void TestSetOutParamterVal()
        {
            mockData.Merge(outMethodData, null);
            IList<object> arguments = new object[] { "Input", "null" };
            mockData.SetOutParamterVal(MethodInfoHelper.GetIOutMethod(), arguments);
            Assert.AreEqual("Input", arguments[0]);
            Assert.AreEqual("Output", arguments[1]);
        }
    }
}
